package com.lt.flashcard.model.service;

import java.util.ArrayList;
import java.util.List;

import org.bson.types.ObjectId;

import com.google.code.morphia.dao.BasicDAO;
import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;
import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.ActionResult;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.entity.Medal;
import com.lt.flashcard.model.entity.Notification;
import com.lt.flashcard.model.entity.User;

public class NotificationService {

    private BasicDAO<Notification, ObjectId> _notificationDAO = null;

    /**
     * Get DAO to interact with database
     * @return
     */
    private BasicDAO<Notification, ObjectId> getNotificationDAO() {
        if (_notificationDAO == null) {
            _notificationDAO = new BasicDAO<Notification, ObjectId>(Notification.class, Repository.getInstance().getDatastore());
        }
        return _notificationDAO;
    }

    /**
     * Get list of 5 latest notifications for a specific user
     * @param user
     * @return
     */
    public List<Notification> getQuickNotificationOfUser(User user) {
        if (user == null) {
            return new ArrayList<Notification>();
        }
        BasicDAO<Notification, ObjectId> srv = getNotificationDAO();
        Query<Notification> query = srv.createQuery();
        query.field("targetuid").equal(user.getId());
        query.order("status");
        query.order("-created");
        query.limit(7);
        return query.asList();
    }

    public void updateUnread(User user) {
        BasicDAO<Notification, ObjectId> srv = getNotificationDAO();
        Query<Notification> query = srv.createQuery();
        query.field("targetuid").equal(user.getId());
        query.field("status").equal(Notification.STATUS_UNREAD);
        List<Notification> list = query.asList();
        for (Notification notification : list) {
            notification.setStatus(Notification.STATUS_READ);
            srv.save(notification);
        }
    }

    /**
     * Update notification to read status
     * @param ids
     */
    public void updateReadNotifications(List<ObjectId> ids) {
        if (ids != null && ids.size() > 0) {
            BasicDAO<Notification, ObjectId> srv = getNotificationDAO();
            Query<Notification> query = srv.createQuery();
            query.field("_id").in(ids);
            UpdateOperations<Notification> update = srv.createUpdateOperations().set("status", Notification.STATUS_READ);
            srv.update(query, update);
        }
    }

    /**
     * Save a notification to database
     * @param notification
     */
    public void saveNotification(Notification notification) {
        BasicDAO<Notification, ObjectId> srv = getNotificationDAO();
        srv.save(notification);
    }

    /**
     * Find notifications that relate to specific source and target
     * @param type
     * @param sourceid
     * @param targetid
     * @return
     */
    public List<Notification> findNotification(int type, Long sourceid, Long targetid) {
        BasicDAO<Notification, ObjectId> dao = getNotificationDAO();
        Query<Notification> query = dao.createQuery();
        query.or(query.and(query.criteria("sourceuid").equal(sourceid), query.criteria("targetuid").equal(targetid)),
                query.and(query.criteria("targetuid").equal(sourceid), query.criteria("sourceuid").equal(targetid)));
        query.field("type").equal(type);
        return query.asList();
    }

    /**
     * Check if friend request is sent
     * @param fromid
     * @param toid
     * @return
     */
    public boolean isSentFriendRequest(Long fromid, Long toid) {
        BasicDAO<Notification, ObjectId> dao = getNotificationDAO();
        Query<Notification> query = dao.createQuery();
        query.or(query.and(query.criteria("sourceuid").equal(fromid), query.criteria("targetuid").equal(toid)),
                query.and(query.criteria("targetuid").equal(fromid), query.criteria("sourceuid").equal(toid)));
        query.field("type").equal(Notification.TYPE_FRIENDREQUEST);
        return query.countAll() > 0l;
    }

    /**
     * System send notification to user
     * @param user
     * @param message
     */
    public void addNotificationSystem(User user, String message) {
        Notification not = new Notification();
        not.setMessage(message);
        not.setTargetuid(user.getId());
        not.setType(Notification.TYPE_SYSTEM);
        saveNotification(not);
    }

    /**
     * User get new medal
     * @param user
     * @param medal
     */
    public void addNotificationGetMedal(User user, Medal medal) {
        Notification not = new Notification();
        not.setTargetuid(user.getId());
        not.setRelatedidstr(medal.getId().toString());
        not.setType(Notification.TYPE_GETMEDAL);
        not.setMessage(String.format("Bạn vừa nhận được huy chương <a class='medal'>\"%s\"</a>", medal.getName()));
        saveNotification(not);
    }

    /**
     * Notification when source rating a flashcardset of target
     * @param source
     * @param target
     * @param flashcardset
     */
    public void addNotificationRating(User source, User target, FlashcardSet flashcardset, int rate) {
        if (source.getId().equals(target.getId())) {
            return;
        }

        Notification not = new Notification();
        not.setImageid(source.getAvatar());
        not.setMessage(String.format("<a href='%s' class='username'>%s</a> đã đánh giá <a href='%s' class='flashcard'>%s</a> của bạn",
                Utility.generateUrl("dashboard", source.getUsername(), null), source.getUsername(),
                Utility.generateUrl("flashcardset", flashcardset.getId(), flashcardset.getName()), flashcardset.getName()));
        not.setRelatedid(flashcardset.getId());
        not.setRelatedname(flashcardset.getName());
        not.setSourceuid(source.getId());
        not.setSourceuname(source.getUsername());
        not.setTargetuid(target.getId());
        not.setType(Notification.TYPE_RATING);
        not.setData(String.valueOf(rate));
        saveNotification(not);
    }

    /**
     * Notification when source want to make friend with target
     * @param source
     * @param target
     * @return result
     */
    public ActionResult addNotificationFriendRequest(User source, User target) {
        ActionResult result = new ActionResult();
        if (source == null || source.getId() == null || target == null || target.getId() == null || source.getId().equals(target.getId())) {
            result.addMessage("Unknow or dupplicate users");
            return result;
        }

        Notification not = new Notification();
        not.setImageid(source.getAvatar());
        not.setMessage(String.format("<a href='%s' class='username'>%s</a> muốn kết bạn với bạn.",
                Utility.generateUrl("dashboard", source.getUsername(), null), source.getUsername()));
        not.setSourceuid(source.getId());
        not.setSourceuname(source.getUsername());
        not.setTargetuid(target.getId());
        not.setType(Notification.TYPE_FRIENDREQUEST);
        saveNotification(not);

        result.setError(false);
        return result;
    }

    /**
     * Notification when source comment on flashcardset
     * @param source
     * @param flashcardset
     */
    public void addNotificationFCSComment(User source, FlashcardSet flashcardset) {
        AAService asrv = Repository.getInstance().getAAService();
        if (asrv.isAdmin(flashcardset.getAuthor())) {
            return;
        }

        Notification not = new Notification();
        not.setImageid(source.getAvatar());
        not.setMessage(String.format("<a href='%s' class='username'>%s</a> đã bình luận <a href='%s'>%s</a>",
                Utility.generateUrl("dashboard", source.getUsername(), null), source.getUsername(),
                Utility.generateUrl("flashcardset", flashcardset.getId(), flashcardset.getName()), flashcardset.getName()));
        not.setRelatedid(flashcardset.getId());
        not.setRelatedname(flashcardset.getName());
        not.setSourceuid(source.getId());
        not.setSourceuname(source.getUsername());
        not.setTargetuid(flashcardset.getAuthor().getId());
        not.setType(Notification.TYPE_COMMENT);
        saveNotification(not);
    }

    /**
     * Notification when source sends private message to target
     * @param source
     * @param target
     */
    public void addNotificationPrivateMessage(User source, User target) {
        Notification not = new Notification();
        not.setImageid(source.getAvatar());
        not.setMessage(String.format("<a href='%s' class='username'>%s</a> gửi bạn tin nhắn",
                Utility.generateUrl("dashboard", source.getUsername(), null), source.getUsername()));
        not.setSourceuid(source.getId());
        not.setSourceuname(source.getUsername());
        not.setTargetuid(target.getId());
        not.setType(Notification.TYPE_PRIVATEMSG);
        saveNotification(not);
    }

    /**
     * Get all notification of a user
     * @param userid
     * @return
     */
    public List<Notification> getAllNotificationOfUser(Long userid) {
        Query<Notification> crit = getNotificationDAO().createQuery();
        crit.field("targetuid").equal(userid);
        crit.order("-created");
        crit.limit(100);
        return crit.asList();
    }
}
